Skip to content

feat: agent keys as Authorization: Bearer, per-client MCP setup in Studio - #38

Merged
Madraka merged 2 commits into
mainfrom
feat/agent-key-bearer
Oct 21, 2026
Merged

Madraka merged 2 commits into
mainfrom
feat/agent-key-bearer

Conversation

@Madraka

@Madraka Madraka commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Summary

API (@cloudhal/api, changeset: minor)

  • /mcp (and /api/me, the only REST route agent keys reach) accept the agent key as Authorization: Bearer <key> as well as x-api-key (agentKeyFrom in auth/types.ts, used by resolvePrincipal). This is what most MCP clients and Codex's bearer_token_env_var send.
  • /api/admin/* keeps Authorization: Bearer <CLOUDHAL_DEPLOY_TOKEN>: the bearer there is never read as an agent key, and an agent key there still gets 401.
  • An unknown bearer is refused; it does not fall back to a browser session sent alongside it. Sessions without a bearer work as before.
  • New shared suite testing-agent-key-auth.ts runs on better-sqlite3 and Miniflare D1.

Studio

  • New McpClientSetup component: pick a client (Claude Code, Codex, Cursor, VS Code, Other; Local (stdio) in the page card) and get ready-to-copy setup for this deployment's /mcp.
  • It shows up in the one-time key reveal with the new key filled in, and in the "Connect an MCP client" card with a placeholder. VS Code's snippet prompts for the key, so the file never holds it. Codex reads it from CLOUDHAL_API_KEY through --bearer-token-env-var.
  • All remote snippets send Authorization: Bearer. The card's header row now shows that too.
  • New strings are in en.ts. The other 18 languages were drafted through i18n:export / i18n:import; they are AI drafts awaiting review.

Docs

  • docs/agents/clients.md: every remote example sends Bearer; Codex uses bearer_token_env_var. It notes that x-api-key still works.
  • Matching one-line updates in docs/agents/README.md, docs/security/threat-model.md and ADR-0011.

Checks (run one after another)

  • packages/api: full vitest run, 30 files / 371 tests passing, including the new suite (8 tests).
  • apps/studio: tsc --noEmit, full vitest run (one design-rules failure, fixed by pointing the required blocks at McpClientSetup), then the touched suites again: 549 passing.
  • pnpm design:lint clean; pnpm size:check ok (the CreateAgentKeyDialog baseline went down).
  • pnpm design:shots of /agents and the key reveal at 1440 and 390 px, against a local throwaway project: no sideways scroll, no console errors.

🤖 Generated with Claude Code

Madraka and others added 2 commits October 21, 2026 11:01
Most MCP clients and Codex's `bearer_token_env_var` send
`Authorization: Bearer <key>`; the API only read `x-api-key`. The principal
resolver now takes either (`agentKeyFrom`). `/api/admin/*` keeps its
deployment-token bearer and never reads it as an agent key; an unknown bearer
is refused rather than falling back to the browser session.

Shared suite on better-sqlite3 and D1: REST and /mcp with Bearer, unknown
bearer, session fallback, deployment token on /api/admin.

Docs: every remote client example sends Bearer (Codex via
bearer_token_env_var); x-api-key stays documented as equivalent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
…reveal

`McpClientSetup` picks a client (Claude Code, Codex, Cursor, VS Code, any
other; local stdio in the page's card) and shows its ready-to-copy setup for
this deployment's /mcp, in the formats of docs/agents/clients.md. Right after a
key is created the secret is filled in; VS Code prompts for it instead of
storing it in the file. All remote snippets send Authorization: Bearer.

Strings in en.ts; other languages drafted through i18n:export/import (AI
drafts awaiting review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
@Madraka
Madraka merged commit 325fe5e into main Oct 21, 2026
4 checks passed
@Madraka
Madraka deleted the feat/agent-key-bearer branch October 21, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant